import { isString } from 'lodash'
import { FormItemRule } from 'naive-ui'

import { App } from 'vue'
// import i18n from '@/language'

declare module '@vue/runtime-core' {
	export interface ComponentCustomProperties {
		$validator: typeof validator
	}
}

// const t = i18n.global.t
type Trigger = 'blur' | 'change' | 'focus' | 'input' | 'clear'

type ValidatorRule = EitherOr<
	FormItemRule & {
		trigger?: Trigger | Trigger[]
		message?: string
	},
	'message',
	'renderMessage'
>

class Validator {
	/** 标签名 */
	private field
	/** 校验规则 */
	private rules

	/**
	 * 生成 Validator 的实例对象
	 * @param rule 校验规则
	 */
	constructor(label: string, rule?: ValidatorRule) {
		this.field = label
		this.rules = [] as ValidatorRule[]
		if (rule) this.rules.push(rule)
	}

	/** 函数包装器 */
	private generateFn(inputRule: any, defaultRule: ValidatorRule) {
		if (inputRule.message || inputRule.renderMessage) {
			delete defaultRule.message
			delete defaultRule.renderMessage
		}
		inputRule = Object.assign(defaultRule, inputRule)
		this.rules.push(inputRule)
		return this
	}

	/**
	 * 检验必填项
	 * @param rule 检验规则
	 * @returns ${field}是必填项
	 */
	required(rule = {} as Omit<ValidatorRule, 'required' | 'whitespace'>): Omit<this, 'required'> {
		return this.generateFn(rule, {
			required: true,
			whitespace: true,
			renderMessage: () => `${this.field}是必填项`,
			trigger: 'blur'
		})
	}

	/**
	 * 检验邮箱格式
	 * @param rule 检验规则
	 * @returns ${field}必须为有效的邮箱
	 */
	email(rule = {} as Omit<ValidatorRule, 'type'>): Omit<this, 'email'> {
		return this.generateFn(rule, {
			type: 'email',
			renderMessage: () => `${this.field}必须为有效的邮箱`,
			trigger: 'blur'
		})
	}

	/**
	 * 检验url格式
	 * @param rule 检验规则
	 * @returns ${field}必须为有效的网址
	 */
	url(rule = {} as Omit<ValidatorRule, 'type'>): Omit<this, 'url'> {
		return this.generateFn(rule, {
			type: 'url',
			renderMessage: () => `${this.field}必须为有效的网址`,
			trigger: 'blur'
		})
	}

	/**
	 * 检验日期格式
	 * @param rule 检验规则
	 * @returns ${field}必须为有效的日期
	 */
	date(rule = {} as Omit<ValidatorRule, 'type'>): Omit<this, 'date'> {
		return this.generateFn(rule, {
			type: 'date',
			renderMessage: () => `${this.field}必须为有效的日期`,
			trigger: 'blur'
		})
	}

	/**
	 * 校验十六进制格式
	 * @param rule 检验规则
	 * @returns ${field}必须为有效的十六进制格式
	 */
	hex(rule = {} as Omit<ValidatorRule, 'type'>): Omit<this, 'hex'> {
		return this.generateFn(rule, {
			type: 'hex',
			renderMessage: () => `${this.field}必须为有效的十六进制格式`,
			trigger: 'blur'
		})
	}

	/**
	 * 检验至少n个字符
	 * @param min 至少n个字符
	 * @param rule 检验规则
	 * @returns ${field}至少${min}个字符
	 */
	min(min: number, rule = {} as Omit<ValidatorRule, 'min'>): Omit<this, 'min'> {
		return this.generateFn(rule, {
			min,
			renderMessage: () => `${this.field}至少${min}个字符`,
			trigger: 'blur'
		})
	}

	/**
	 * 校验至多n个字符
	 * @param max 至多n个字符
	 * @param rule 校验规则
	 * @returns `${field}至多${max}个字符
	 */
	max(max: number, rule = {} as Omit<ValidatorRule, 'max'>): Omit<this, 'max'> {
		return this.generateFn(rule, {
			max,
			renderMessage: () => `${this.field}至多${max}个字符`,
			trigger: 'blur'
		})
	}

	/**
	 * 校验必须n个字符
	 * @param len 必须n个字符
	 * @param rule 校验规则
	 * @returns `${field}必须是${len}个字符
	 */
	len(len: number, rule = {} as Omit<ValidatorRule, 'len'>): Omit<this, 'len'> {
		return this.generateFn(rule, {
			len,
			renderMessage: () => `${this.field}至多${len}个字符`,
			trigger: 'blur'
		})
	}

	/**
	 * 校验枚举
	 * @param enumList 枚举列表
	 * @param rule 校验规则
	 * @returns `${field}必须是${enumList.join('、')}中的其中一项`
	 */
	enum(enumList: string[], rule = {} as Omit<ValidatorRule, 'type' | 'enum'>): Omit<this, 'enum'> {
		return this.generateFn(rule, {
			type: 'enum',
			enum: enumList,
			renderMessage: () => `${this.field}必须是${enumList.join('、')}中的其中一项`,
			trigger: 'blur'
		})
	}

	/**
	 * 自定义匹配
	 * @param pattern 自定义正则表达式或字符串
	 * @param message 提示消息
	 * @param rule 校验规则
	 * @returns ${message}
	 */
	match(
		pattern: RegExp | string,
		message: string | (() => string),
		rule = {} as Omit<ValidatorRule, 'pattern' | 'message' | 'renderMessage'>
	): this {
		return this.generateFn(rule, {
			pattern,
			message: isString(message) ? message : undefined,
			renderMessage: isString(message) ? undefined : (message as any),
			trigger: 'blur'
		})
	}

	/** 返回校验规则 */
	val() {
		return Object.freeze(this.rules) as ValidatorRule
	}
}

/**
 * form表单校验规则
 * @param field 标签名，默认“该项”
 * @param rule 校验规则
 * @returns Validator实例对象
 */
export const validator = (field = '该项', rule?: ValidatorRule) => new Validator(field, rule)

export default {
	install: (app: App) => (app.config.globalProperties.$validator = validator)
}
